package com.nets.decoder;

import com.alibaba.fastjson.JSON;
import com.nets.packet.AbstractPacket;
import com.nets.packet.PacketTypeI;
import com.nets.pool.NetPool;
import com.nets.pool.ServerPool;
import com.nets.util.LogUtil;
import com.nets.util.ZipUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.CharsetUtil;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @author sig
 * @since 2016/9/17
 */
public class PacketDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx,
                          ByteBuf in,
                          List<Object> out) throws Exception {
        if (0 >= in.readableBytes()) return;
        byte head = in.readByte(); // 帧头

        if (-11 != head) return;
        in.readerIndex(in.writerIndex() - 1);
        byte tail = in.readByte(); // 帧尾

        if (-99 != tail) return;
        in.readerIndex(0);
        in.readByte(); // 跳过帧头
        byte isZip = in.readByte(); // 压缩标记
        int length = in.readInt();
        int type = in.readInt();
        byte[] data = new byte[length];
        in.readBytes(data);
        in.readByte(); // 跳过帧尾

        if (1 == isZip) data = ZipUtil.unGZip(data);
        String jsonStr = new String(data, CharsetUtil.UTF_8);

        if (null != LogUtil.console && ServerPool.logSwitch)
            LogUtil.console.info("The client request type:"
                    + type + "|packet:" + jsonStr);
        Class<?> clazz = Class.forName(NetPool.packet);
        AbstractPacket packet = (AbstractPacket) clazz.newInstance(); // 通过构造方法实例化Packet对象

        clazz = Class.forName(NetPool.packetType);
        Method method = clazz.getMethod(NetPool.getPacketType, Integer.TYPE);
        PacketTypeI packetType = (PacketTypeI) method.invoke(clazz, type); // 调用PacketType的成员方法

        packet.setObject(JSON.parseObject(jsonStr));
        packet.setPacketType(packetType);
        packet.setChannel(ctx.channel());
        out.add(packet);
    }
}
